package com.telit.firecommand.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.xiaolyuh.annotation.CacheEvict;
import com.github.xiaolyuh.annotation.Cacheable;
import com.telit.common.constant.ForestResultConstants;
import com.telit.common.constant.MsgIdentificationConstants;
import com.telit.common.core.utils.FeignUtils;
import com.telit.common.entity.DataReturn;
import com.telit.common.exception.ForestBaseException;
import com.telit.communicate.dto.SendMessageDTO;
import com.telit.communicate.feign.RemoteCommunicateService;
import com.telit.firecommand.dao.*;
import com.telit.firecommand.dto.PlotDetailsDto;
import com.telit.firecommand.dto.PlotDto;
import com.telit.firecommand.dto.PlotReturnDto;
import com.telit.firecommand.entity.*;
import com.telit.firecommand.service.ICadPlotService;
import com.telit.upms.feign.RemoteUpmsService;
import com.telit.upms.vo.MicroSysUserVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


/**
 * <p>
 * 联动标绘 服务实现类
 * </p>
 *
 * @author yummy
 * @since 2021-07-31
 */
@Service
@Transactional
public class CadPlotServiceImpl extends ServiceImpl<CadPlotDao, CadPlot> implements ICadPlotService {

    @Autowired
    private CadPlotAttachmentDao cadPlotAttachmentDao;

    @Autowired
    private CadPlotRoomDao cadPlotRoomDao;

    @Autowired
    private CadPlotActionDao cadPlotActionDao;

    @Autowired
    private CadPlotIconDao cadPlotIconDao;

    @Autowired
    private RemoteCommunicateService communicateFeignClient;

    @Autowired
    private RemoteUpmsService remoteUpmsService;

    @Override
    @CacheEvict(value = {"firecommand:plot:searchByFireAlarmId",
            "firecommand:plot:searchDetailsByFireAlarmId"}, allEntries = true)
    public Long add(PlotDto plotDto) {
        //插入主表
        CadPlot cadPlot = plotDto.getCadPlot();
        Date createTime = cadPlot.getCreateTime();
        if (createTime == null) {
            createTime = new Date();
            cadPlot.setCreateTime(createTime);
        }
        baseMapper.insert(cadPlot);
        Long cadPlotId = cadPlot.getId();

        //插入附表判断
        if (null != cadPlot.getIconId()) {
            CadPlotAttachment cadPlotAttachment = plotDto.getCadPlotAttachment();
            cadPlotAttachment.setCadPlotId(cadPlotId);
            cadPlotAttachmentDao.insert(cadPlotAttachment);
        }

        //获取userId
        Long userId = cadPlot.getUserId();
        //判断action状态是否为进入/退出房间
        CadPlotRoom cadPlotRoom = new CadPlotRoom().setFireAlarmId(cadPlot.getFireAlarmId()).setUserId(userId);
        //进入房间的个数
        Integer inCount = cadPlotRoomDao.selectCount(
                new QueryWrapper<CadPlotRoom>().eq("user_id", userId).eq("fire_alarm_id", cadPlot.getFireAlarmId()).eq(
                        "status", "1"));
        if (cadPlot.getActionId() == 3) {
            if (inCount == 0) {
                cadPlotRoomDao.insertSelective(cadPlotRoom.setCreateTime(createTime).setStatus("1"));
                //推送联动标绘人数+1
                communicateFeignClient.sendMsg(new SendMessageDTO("web",
                        JSON.toJSONString(DataReturn.ok(MsgIdentificationConstants.USER_IN_OUT, userId))));
            } else {
                //进入房间失败
                throw new ForestBaseException(ForestResultConstants.IN_OUT_FALSE,
                        ForestResultConstants.IN_OUT_FALSE_MSG);
            }
        }
        if (cadPlot.getActionId() == 8) {
            //当前用户在房间
            if (inCount == 1) {
                cadPlotRoomDao.update(cadPlotRoom.setUpdateTime(createTime).setStatus("0"),
                        new UpdateWrapper<CadPlotRoom>().eq("fire_alarm_id", cadPlot.getFireAlarmId()).eq("user_id",
                                userId));
                //推送联动标绘人数-1
                communicateFeignClient.sendMsg(new SendMessageDTO("web",
                        JSON.toJSONString(DataReturn.ok(MsgIdentificationConstants.USER_IN_OUT, userId))));
            } else {
                //推送联动标绘人数0,代表退出房间失败
                //进入房间失败
                throw new ForestBaseException(ForestResultConstants.IN_OUT_FALSE,
                        ForestResultConstants.IN_OUT_FALSE_MSG);
            }
        }

        //返回bean定义
        PlotDetailsDto plotDetailsDto = new PlotDetailsDto();
        plotDetailsDto.setFireAlarmId(cadPlot.getFireAlarmId());
        plotDetailsDto.setId(cadPlotId);
        plotDetailsDto.setCadPlotAttachment(plotDto.getCadPlotAttachment());
        //填充用户ID
        plotDetailsDto.setUserId(userId);
        //根据操作ID查询操作详情
        CadPlotAction cadPlotAction = cadPlotActionDao.selectByActionValue(cadPlot.getActionId());
        plotDetailsDto.setCadPlotAction(cadPlotAction);
        //根据图形ID查询图形详情
        CadPlotIcon cadPlotIcon = cadPlotIconDao.selectById(cadPlot.getIconId());
        plotDetailsDto.setCadPlotIcon(cadPlotIcon);
        //推送联动标绘
        communicateFeignClient.sendMsg(new SendMessageDTO("web",
                JSON.toJSONString(DataReturn.ok(MsgIdentificationConstants.LINKAGE_PLOTTING, plotDetailsDto))));

        return cadPlotId;
    }

    @Override
    @CacheEvict(value = {"firecommand:plot:searchByFireAlarmId",
            "firecommand:plot:searchDetailsByFireAlarmId"}, allEntries = true)
    public int delete(Integer id) {
        return baseMapper.deleteById(id);
    }

    @Override
    @CacheEvict(value = {"firecommand:plot:searchByFireAlarmId",
            "firecommand:plot:searchDetailsByFireAlarmId"}, allEntries = true)
    public List<Integer> deleteBatch(Integer[] ids) {
        List<Integer> values = new ArrayList<Integer>();
        if (ids != null && ids.length > 0) {
            for (Integer id : ids) {
                values.add(delete(id));
            }
        }
        return values;
    }

    @Override
    @CacheEvict(value = {"firecommand:plot:searchByFireAlarmId",
            "firecommand:plot:searchDetailsByFireAlarmId"}, allEntries = true)
    public int updateData(CadPlot cadPlot) {
        return baseMapper.updateById(cadPlot);
    }

    @Override
    public CadPlot findById(Integer id) {
        return baseMapper.selectById(id);
    }

    @Override
    public List<PlotReturnDto> searchByFireAlarmId(String fireAlarmId) {
        //2022-05-18 优化 避免过度请求 -------fixed by yzx-------start
        //根据火情ID查询标绘数据
       /* List<PlotReturnDto> plotReturnDtoList = baseMapper.searchByFireAlarmId(fireAlarmId);
        //根据用户ID查询用户姓名
        if (plotReturnDtoList != null && plotReturnDtoList.size() > 0) {
            for (PlotReturnDto plotReturnDto : plotReturnDtoList) {
                SysUserDetailVo sysUserVo = userInfoService.getUserInfo(plotReturnDto.getUserId());
                plotReturnDto.setUsername(sysUserVo == null ? null : sysUserVo.getRealName());
            }
        }
        return plotReturnDtoList;*/
        final List<PlotReturnDto> plotReturnDtoList = baseMapper.searchByFireAlarmId(fireAlarmId);
        if (CollUtil.isEmpty(plotReturnDtoList)) {
            return plotReturnDtoList;
        }
        final List<Long> ids = plotReturnDtoList.stream()
                .filter(plotReturnDto -> ObjectUtil.isNotEmpty(plotReturnDto.getUserId()))
                .map(PlotReturnDto::getUserId)
                .distinct()
                .collect(Collectors.toList());
        //处理用户名称
        Map<Long, MicroSysUserVo> microSysUserVoMap = new HashMap<>();
        if (CollUtil.isNotEmpty(ids)) {
            com.telit.common.core.utils.Result<Map<Long, MicroSysUserVo>> selectByBatchIdsResult = remoteUpmsService.selectByBatchIds(
                    ids, true);
            microSysUserVoMap = FeignUtils.unwrap(selectByBatchIdsResult);
        }
        Map<Long, MicroSysUserVo> finalMicroSysUserVoMap = microSysUserVoMap;
        plotReturnDtoList.forEach(dto -> {
            dto.setUsername(finalMicroSysUserVoMap.get(dto.getUserId()) != null ? finalMicroSysUserVoMap.get(
                    dto.getUserId()).getRealName() : "");
        });
        return plotReturnDtoList;
        //2022-05-18 优化 避免过度请求 -------fixed by yzx-------end
    }

    @Override
    @Cacheable(value = "firecommand:plot:searchDetailsByFireAlarmId", depict = "根据火情ID查询联动标绘地图信息", key = "#p0")
    public List<PlotDetailsDto> searchDetailsByFireAlarmId(String fireAlarmId) {
        Integer[] actionId = {1, 2, 3, 8};
        return searchDetailByFireAlarmIdAndActionId(fireAlarmId, actionId);
    }

    @Override
    public List<PlotDetailsDto> searchAllDetailsByFireAlarmId(String fireAlarmId) {
        Integer[] actionId = {1, 2};
        return searchDetailByFireAlarmIdAndActionId(fireAlarmId, actionId);
    }

    private List<PlotDetailsDto> searchDetailByFireAlarmIdAndActionId(String fireAlarmId, Integer... actionIdStr) {
        //2022-05-18 优化 避免过度请求 -------fixed by yzx-------start
     /*   List<CadPlot> cadPlotList = baseMapper.selectList(new QueryWrapper<CadPlot>().eq("fire_alarm_id", fireAlarmId).notIn("action_id", actionIdStr).orderByAsc("create_time"));
        List<PlotDetailsDto> plotDetailsDtoList = new ArrayList<>();
        if (cadPlotList != null && cadPlotList.size() > 0) {
            for (CadPlot cadPlot :
                    cadPlotList) {
                //属性赋值
                PlotDetailsDto plotDetailsDto = new PlotDetailsDto();
                BeanUtil.copyProperties(cadPlot, plotDetailsDto);
                //用户名
                SysUserDetailVo sysUserVo = userInfoService.getUserInfo(cadPlot.getUserId());
                plotDetailsDto.setUserName(sysUserVo.getRealName());
                //根据操作ID查询操作详情
                CadPlotAction cadPlotAction = cadPlotActionDao.selectByActionValue(cadPlot.getActionId());
                plotDetailsDto.setCadPlotAction(cadPlotAction);
                //根据图形ID查询图形详情
                CadPlotIcon cadPlotIcon = cadPlotIconDao.selectById(cadPlot.getIconId());
                plotDetailsDto.setCadPlotIcon(cadPlotIcon);
                //根据主表ID查询附表
                CadPlotAttachment cadPlotAttachment = cadPlotAttachmentDao.selectByCadPlotId(cadPlot.getId());
                plotDetailsDto.setCadPlotAttachment(cadPlotAttachment);
                plotDetailsDtoList.add(plotDetailsDto);
            }
        }
        return plotDetailsDtoList;*/
        List<CadPlot> cadPlotList = baseMapper.selectList(
                new QueryWrapper<CadPlot>().eq("fire_alarm_id", fireAlarmId).notIn("action_id", actionIdStr).orderByAsc(
                        "create_time"));


        List<Long> ids = new ArrayList<>();
        if (CollUtil.isNotEmpty(cadPlotList)) {
            ids = cadPlotList.parallelStream().map(CadPlot::getUserId).collect(Collectors.toList());
        }

        //处理用户名称
        Map<Long, MicroSysUserVo> microSysUserVoMap = new HashMap<>();
        if (CollUtil.isNotEmpty(ids)) {
            com.telit.common.core.utils.Result<Map<Long, MicroSysUserVo>> selectByBatchIdsResult = remoteUpmsService.selectByBatchIds(
                    ids, true);
            microSysUserVoMap = FeignUtils.unwrap(selectByBatchIdsResult);
        }
        Map<Long, MicroSysUserVo> finalMicroSysUserVoMap = microSysUserVoMap;

        List<PlotDetailsDto> plotDetailsDtoList = new ArrayList<>();
        if (cadPlotList != null && cadPlotList.size() > 0) {
            ArrayList<Long> cadPlotIdList = CollectionUtil.newArrayList();
            for (CadPlot cadPlot :
                    cadPlotList) {
                //属性赋值
                PlotDetailsDto plotDetailsDto = new PlotDetailsDto();
                BeanUtil.copyProperties(cadPlot, plotDetailsDto);
                //用户名
                plotDetailsDto.setUserName(
                        finalMicroSysUserVoMap.get(cadPlot.getUserId()) != null ? finalMicroSysUserVoMap.get(
                                cadPlot.getUserId()).getRealName() : "");
                //根据操作ID查询操作详情，此部分不进行一次性查询出来的原因是总共就9条数据，一般不会改变，如果进行集合查询，虽然短期内查询次数降低，但是随着火情越来越多，
                //查询次数也会增多，所以只做了缓存操作，拿极值算也只会查询9次
                CadPlotAction cadPlotAction = cadPlotActionDao.selectByActionValue(cadPlot.getActionId());
                plotDetailsDto.setCadPlotAction(cadPlotAction);
                //根据图形ID查询图形详情，以下暂时不进行集合查询，理由同上，总共就20条不怎么会变动的数据
                CadPlotIcon cadPlotIcon = cadPlotIconDao.selectByIconId(cadPlot.getIconId());
                plotDetailsDto.setCadPlotIcon(cadPlotIcon);
                //获取标绘的ID存入集合
                cadPlotIdList.add(cadPlot.getId());
                //根据主表ID查询附表，此代码存在查询很多次的情况，注释掉，优化在下面
                /*CadPlotAttachment cadPlotAttachment = cadPlotAttachmentDao.selectByCadPlotId(cadPlot.getId());
                plotDetailsDto.setCadPlotAttachment(cadPlotAttachment);*/
                plotDetailsDtoList.add(plotDetailsDto);
            }
            //优化开始,根据标绘ID集合查询标绘附属信息
            Map<Long, CadPlotAttachment> retCadPlotAttachmentMap = CollectionUtil.newHashMap();
            List<CadPlotAttachment> cadPlotAttachmentList = cadPlotAttachmentDao.selectListByCadPlotIdList(
                    cadPlotIdList);
            if (CollectionUtil.isNotEmpty(cadPlotAttachmentList)) {
                retCadPlotAttachmentMap = cadPlotAttachmentList.stream().collect(
                        Collectors.toMap(CadPlotAttachment::getCadPlotId, e -> e));
            }
            //设置附属信息
            Map<Long, CadPlotAttachment> finalRetCadPlotAttachmentMap = retCadPlotAttachmentMap;
            plotDetailsDtoList.forEach(e -> {
                e.setCadPlotAttachment(finalRetCadPlotAttachmentMap.get(e.getId()));
            });

        }
        return plotDetailsDtoList;
        //2022-05-18 优化 避免过度请求 -------fixed by yzx-------end
    }


    @Override
    public IPage<CadPlot> findListByPage(CadPlot cadPlot, Integer page, Integer pageCount) {
        IPage<CadPlot> cadPlotPage = new Page<>(page, pageCount);
        QueryWrapper<CadPlot> wrapper = new QueryWrapper<>();
        if (cadPlot != null) {
        }
        return baseMapper.selectPage(cadPlotPage, wrapper);
    }

    @Override
    public List<CadPlot> searchNoPage(CadPlot cadPlot) {
        QueryWrapper<CadPlot> wrapper = new QueryWrapper<>();
        if (cadPlot != null) {
        }
        return baseMapper.selectList(wrapper);
    }

}
